package cn.finder.httpcommons.parser;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import cn.finder.httpcommons.attri.JsonArrayAttribute;
import cn.finder.httpcommons.attri.JsonArrayItemAttribute;
import cn.finder.httpcommons.attri.JsonProperty;
import cn.finder.httpcommons.response.ApiResponse;
import cn.finder.httpcommons.utils.CommonUtils;
import cn.finder.httpcommons.utils.DateUtils;
import cn.finder.httpcommons.utils.JsonUtils;

/***
 * Json 解析器
 * @author dragon
 *
 */
public class JsonParser<T extends ApiResponse> implements IParser<T>{

	 // Fields
    private  Map<String, Map<String, ApiAttribute>> attrs;
	
	
		

        public JsonParser()
        {
        	 attrs = new HashMap<String, Map<String, ApiAttribute>>();
        }
        public Object fromJson(IReader reader, Class<Object> type)
        {

            Object retObj = null;
            
            if(type.equals(HashMap.class)){
            	//如果是map类型
            	retObj=reader.getData();
            	return retObj;
            }
            
            
           Map<String,ApiAttribute>  attributes =  getAttributes(type);
           Set<Entry<String,ApiAttribute>> setEntry = attributes.entrySet();
           
           Iterator<Entry<String,ApiAttribute>>   itr =  setEntry.iterator();
           
           while (itr.hasNext())
           {
        	   Entry<String, ApiAttribute> current =itr.next();
               ApiAttribute attribute = current.getValue();


               String itemName = attribute.getItemName();
               String listName = attribute.getListName();
               
               if (reader.hasReturnField(itemName) || (!CommonUtils.isEmpty(listName) && reader.hasReturnField(listName)))
               {
                   Object value = null;
                   try
                   {
	                   if (attribute.getListType() != null)
	                   {
	                       value = reader.getListObjects(listName, itemName, attribute.getListType(),attribute.getItemType());
	                   }
	                   else if (attribute.getItemType().getName().indexOf("String")!=-1)
	                   {
	                       Object primitiveObject = reader.getPrimitiveObject(itemName);
	                       if (primitiveObject != null)
	                       {
	                           value = primitiveObject.toString();
	                       }
	                   }
	                   // new add
	                   else if (attribute.getItemType().getName().indexOf("int")!=-1)
	                   {
	                       Object primitiveObject = reader.getPrimitiveObject(itemName);
	                       if (primitiveObject != null)
	                       {
	                           value = Integer.valueOf(primitiveObject.toString());
	                       }
	                   }
	
	                   else if (attribute.getItemType().getName().indexOf("float")!=-1)
	                   {
	                       Object primitiveObject = reader.getPrimitiveObject(itemName);
	                       if (primitiveObject != null)
	                       {
	                    	   value = Float.valueOf(primitiveObject.toString());
	                       }
	                   }
	                   else if (attribute.getItemType().getName().indexOf("double")!=-1)
	                   {
	                       Object primitiveObject = reader.getPrimitiveObject(itemName);
	                       if (primitiveObject != null)
	                       {
	                    	   value = Double.valueOf(primitiveObject.toString());
	                       }
	                   }
	
	                   else if (attribute.getItemType().getName().indexOf("long")!=-1)
	                   {
	                       Object primitiveObject = reader.getPrimitiveObject(itemName);
	                       if (primitiveObject != null)
	                       {
	                    	   value = Long.valueOf(primitiveObject.toString());
	                       }
	                   }
	                   else if (attribute.getItemType().getName().indexOf("boolean")!=-1)
	                   {
	                       value = reader.getPrimitiveObject(itemName);
	                   }
	                   
	                   else if (attribute.getItemType().isArray())
	                   {//数组-基础
	                       Object primitiveObject = reader.getArrayObject(itemName);
	                       if (primitiveObject != null)
	                       {
	                    	   value = primitiveObject;
	                       }
	                   }
	                   else if (attribute.getItemType().getName().indexOf("Date")!=-1)
	                   {
	                       Object primitiveObject = reader.getPrimitiveObject(itemName);
	                       if (primitiveObject == null)
	                       {
	
	                       }
	                       else if (primitiveObject != null && !"".equals(primitiveObject))
	                       {
	                           
	                           Date dt = DateUtils.parseDate(primitiveObject.toString());
	
	                           value = dt;
	                       }
	                   }
	                   
	                   else
	                   {
	                       value = reader.getReferenceObject(itemName, attribute.getItemType()/*, new DConvert(this.FromJson)*/);
	                   }
	                   if (value != null)
	                   {
	                       if (retObj == null)
	                       {
	                           try {
									retObj = type.newInstance();
								} catch (Exception e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
	                       }
	                       Object[] parameters = new Object[] { value };
	                       
	                       try {
	                    	   //System.out.println("attributee:"+attribute.getMethod().getName()+" "+parameters[0].toString());
								attribute.getMethod().invoke(retObj, parameters);
								 //System.out.println("attributee:"+attribute.getMethod().getName()+" "+parameters[0].toString());
							} catch (Exception e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
	                   }
                   }
                   catch(Exception e)
                   {
                	   e.printStackTrace();
                   }
               }
           }
           return retObj;
            

        }


        /***
         * 获取 类型下的属性 对应的具体属性 是单个对象 还是结合等 
         * @param type
         * @return
         */
        private Map<String, ApiAttribute> getAttributes(Class<Object> type)
        {
        	
        	
        	Map<String, ApiAttribute> dictionary = null;
        	dictionary = attrs.get(type.getName());
        	 if (dictionary==null)
             {
                 dictionary = new HashMap<String, ApiAttribute>();
                 for (Method method : type.getMethods())
                 {
                	 ApiAttribute attribute = new ApiAttribute();
                	 
                	 if(method.getModifiers() ==Modifier.PUBLIC){
                		 
                		 String methodName = method.getName();
                		 if(methodName.startsWith("set")){
                			 attribute.setMethod(method);
                			 
                			 
                			 JsonArrayItemAttribute jsonArrayItemAttribute = method.getAnnotation(JsonArrayItemAttribute.class);
                    		 if(jsonArrayItemAttribute!=null){
                    			 attribute.setItemName(jsonArrayItemAttribute.name());
                    			 attribute.setItemType(jsonArrayItemAttribute.clazzType());
                    		 }
                    		 
                    		 JsonArrayAttribute jsonArrayAttribute = method.getAnnotation(JsonArrayAttribute.class);
                    		 if(jsonArrayAttribute!=null){
                    			 attribute.setListName(jsonArrayAttribute.name());
                    		 }
                    		 
                    		 if(jsonArrayAttribute==null){
                    			 JsonProperty jsonProperty = method.getAnnotation(JsonProperty.class);
                    			 if(jsonProperty!=null){
                    				 attribute.setItemName(jsonProperty.name());
                    			 }
                    			 else{
                    				 //setNewName  -> NewName
                    				 String newTmpStr = methodName.substring(3);
                    				 String propName = newTmpStr.substring(0, 1).toLowerCase()+newTmpStr.substring(1);
                                     attribute.setItemName(propName);
                    			 }
                    		 }
                    		 
                    		  
                    		  
                    		 Class<?> c= method.getParameterTypes()[0];
                    		// Class trueType = ((ParameterizedType) ctype).getActualTypeArguments()[0];
                    		 
                    		// Type[] params = ((ParameterizedType) c).getActualTypeArguments();
                    		 
                    		 
                    		 if (c.getName().equals(java.util.List.class.getName()))
                             {//这里应该获取泛型的真实类型   但是获取不到
                    			 //要么ApiResponse<T> 要么所有的 自定义响应  有同一个方法 ApiObject findEntityType()
                    			/* Type genType = c.getGenericSuperclass();
                    			 Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
                    			 Class trueType=params[0].getClass();*/
                    			 attribute.setListType(List.class);
                    			 
                             }
                             else
                             {
                                 attribute.setItemType((Class)c);
                             }
                             dictionary.put(methodName, attribute);
                             
                             
                             
                             attrs.put(type.getName(), dictionary);
                		 }
                		 
                		 
                		 
                	 }
                	 
                 }
                
             }
        	return dictionary;
        }
       
        
        @SuppressWarnings("unchecked")
		public  T parse(String body,Class<Object> type) {
        	
           T resp=null;
           
           Map<String,Object> dictionary=null;
           
           try{
        	   dictionary = JsonUtils.getMap4Json(body);
           }
           catch(Exception e)
           {
        	   
           }
          
            if (dictionary == null)
            {
                if (resp == null)
                {
                    try {
						resp = (T)type.newInstance();
					} catch (Exception e) {
						e.printStackTrace();
					} 
                    
                }
                if (resp != null)
                {
                    resp.setBody(body);
                }
            }
            else
            {
            	
            	
                IReader reader = new JsonReader(dictionary);
                resp = (T)this.fromJson(reader,type);
                if (resp == null)
                {
                	try {
						resp = (T) type.newInstance();
					} catch (Exception e) {
						e.printStackTrace();
					} 
                }
                else
                {
                    resp.setBody(body);
                }

            }
            return resp;

        }

}
